
/**
  ******************************************************************************
  * Copyright 2021 The grapilot Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       uITC.c
  * @author     baiyang
  * @date       2021-7-13
  ******************************************************************************
  */

/*----------------------------------include-----------------------------------*/
#include <string.h>
#include "uITC.h"
#include <common/console/console.h>
/*-----------------------------------macro------------------------------------*/

/*----------------------------------typedef-----------------------------------*/

/*---------------------------------prototype----------------------------------*/

/*----------------------------------variable----------------------------------*/
static char* TAG = "uITC: ";
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
/**
  * @brief       
  * @param[in]   hub  
  * @param[out]  
  * @retval      
  * @note        
  */
int8_t itc_advertise(itc_hub* hub)
{
    int res = 0;
    
    if(hub->pdata != NULL){
        // already advertised
        return 0;
    }
    
    ITC_ENTER_CRITICAL;
    hub->pdata = ITC_MALLOC(hub->obj_size);
    if(hub->pdata == NULL){
        res = 1;
    }
    ITC_EXIT_CRITICAL;
   
    return res;
}

/**
  * @brief       
  * @param[in]   hub  
  * @param[in]   cb  
  * @param[in]   parameter  
  * @param[out]  
  * @retval      
  * @note        
  */
itc_node_t itc_subscribe(itc_hub* hub, void (*cb)(void *parameter))
{
    if (hub == NULL) {
        return NULL;
    }
    
    if(hub->link_num >= ITC_MAX_LINK_NUM){
        console_printf("%s: itc link num is already full!\n",TAG);
        return NULL;
    }

    itc_node_t node = (itc_node_t)ITC_MALLOC(sizeof(itc_node));
    if(node == NULL){
        console_printf("%s: itc create node fail!\n",TAG);
        return NULL;
    }
    node->renewal = 0;
    node->cb = cb;
    node->next = NULL;

    ITC_ENTER_CRITICAL;
    /* no node link yet */
    if(hub->link_tail == NULL){
        hub->link_head = hub->link_tail = node;
    }else{	
        hub->link_tail->next = node;
        hub->link_tail = node;
    }
    hub->link_num++;
    ITC_EXIT_CRITICAL;

    return node;
}

/**
  * @brief       
  * @param[in]   hub  
  * @param[in]   data  
  * @param[out]  
  * @retval      
  * @note        
  */
int8_t itc_publish(itc_hub* hub, const void* data)
{
    if(data == NULL){
        console_printf("%s: null data publish!\n",TAG);
        return -1;
    }

    if(hub->pdata == NULL){
        // hub is not advertised yet
        return -2;
    }

    ITC_ENTER_CRITICAL;
    /* copy data to hub */
    rt_memcpy(hub->pdata, data, hub->obj_size);
    /* update each node's renewal flag */
    itc_node_t node = hub->link_head;
    while(node != NULL){
        node->renewal = 1;
        node = node->next;
    }
    hub->published = 1;
    ITC_EXIT_CRITICAL;

    /* invoke callback func */
    node = hub->link_head;
    while(node != NULL){
        if(node->cb != NULL){
            node->cb(hub->pdata);
        }
        node = node->next;
    }

    return 0;
}

/**
  * @brief       
  * @param[in]   node_t  
  * @param[out]  
  * @retval      
  * @note        
  */
bool itc_update(itc_node_t node_t)
{
    bool renewal = 0;
    
    if (node_t != NULL) {
        ITC_ENTER_CRITICAL;
        renewal = node_t->renewal;
        ITC_EXIT_CRITICAL;
    }
    
    return renewal;
}

/**
  * @brief       
  * @param[in]   node_t  
  * @param[in]   update  
  * @param[out]  
  * @retval      
  * @note        
  */
bool itc_check(itc_node_t node_t, bool* update)
{
    if (node_t == NULL)
    {
        console_printf("%s: node is null\n",TAG);
        return 0;
    }

    ITC_ENTER_CRITICAL;
    *update = node_t->renewal;
    ITC_EXIT_CRITICAL;

    return 0;
}

/**
  * @brief       
  * @param[in]   hub  
  * @param[in]   node_t  
  * @param[in]   buffer  
  * @param[out]  
  * @retval      
  * @note        
  */
int8_t itc_copy(itc_hub* hub, itc_node_t node_t, void* buffer)
{
    if(hub->pdata == NULL){
        // not advertised yet
        console_printf("%s: itc_copy from null hub:%s\n", TAG, hub->obj_name);
        return -1;
    }
    if(!hub->published){
        // copy before published
        return -2;
    }

    ITC_ENTER_CRITICAL;
    rt_memcpy(buffer, hub->pdata, hub->obj_size);
    node_t->renewal = 0;
    ITC_EXIT_CRITICAL;

    return 0;
}

/**
  * @brief       
  * @param[in]   hub  
  * @param[in]   buffer  
  * @param[out]  
  * @retval      
  * @note        
  */
int8_t itc_copy_from_hub(itc_hub* hub, void* buffer)
{
    if(hub->pdata == NULL){
        // not advertised yet
        console_printf("%s: copy_from_hub from null hub:%s\n", TAG, hub->obj_name);
        return -1;
    }
    if(!hub->published){
        // copy before published
        return -2;
    }
    
    ITC_ENTER_CRITICAL;
    rt_memcpy(buffer, hub->pdata, hub->obj_size);
    ITC_EXIT_CRITICAL;
    
    return 0;
}

/*------------------------------------test------------------------------------*/


